package mysqlgo

import (
	"errors"
	"fmt"
	"strings"
)

var builder SQLBuilder

//Model 表模型
type Model struct{
	DBAlias		string
	TableName 	string
	Prefix		string
	err			[]string
	sql			string
	options		option
}

//NewModel 创建Model
func NewModel(options ...OptionModel) *Model {
	m := new(Model) 
	for _, o := range options {
		o(m)
	}
	return m
}

//OptionModel 参数模型
type OptionModel func(*Model)

//TableModel 表模型
func TableModel(tableName , dbAlias string) OptionModel {
	return func(m *Model) {
		m.TableName = tableName
		m.DBAlias = dbAlias
		m.options.setTable(Table{
			Name : tableName, 
		})
	}
}

func (m *Model) parseOption(){
	if len(m.options.tables) == 0 {
		m.options.setTable(Table{
			Name : m.getTableName(),
		})
	}
}

func (m *Model) getDBAlias() string {
	if m.DBAlias == "" {
		return "default"
	}
	return m.DBAlias
}

func (m *Model) getTableName() string {
	if m.TableName == "" {
		m.err = append(m.err, "[Model getTableName]: The TableName is nil")
	}
	return m.TableName
}

//ModelHook 模型操作前预处理数据钩子函数
type ModelHook interface {
	
}

//Table 指定当前的数据表
func (m *Model) Table(tables ...Table) *Model {
	m.options.setTable(tables...)
	return m
}

//Field 指定字段名
func (m *Model) Field(fields ...string) *Model {
	m.options.setField(fields...)
	return m
}

//Where 指定查询条件
func (m *Model) Where(where string, args ...interface{}) (model *Model) {
	defer func(){
		if err := recover(); err != nil {
			m.err = append(m.err, err.(string))
		}
	}()
	m.options.setWhere(where, args...)
	return m
}

//Order 对操作的结果排序
func (m *Model) Order(orders ...Order) *Model {
	m.options.setOrder(orders...)
	return m
}

//Limit 指定查询和操作的数量
func (m *Model) Limit(limit Limit) *Model {
	m.options.setLimit(limit)
	return m
}

//Page 指定分页
///page 页数
///listRows 每页数量
func (m *Model) Page(page uint, listRows uint) *Model {
	m.options.setPage(page, listRows)
	return m
}

//Group 一个或多个列对结果集进行分组
func (m *Model) Group(fields ...string) *Model {
	m.options.setGroup(fields...)
	return m
}

//Having 配合group方法完成从分组的结果中筛选
func (m *Model) Having(having string) *Model {
	m.options.setHaving(having)
	return m
}

//Distinct 用于返回唯一不同的值
func (m *Model) Distinct(distinct bool) *Model {
	m.options.setDistinct(distinct)
	return m
}

//Join 用于根据两个或多个表中的列之间的关系，从这些表中查询数据
func (m *Model) Join(join Join) *Model {
	m.options.setJoin(join)
	return m
}

//Union 用于合并两个或多个SELECT语句的结果集
func (m *Model) Union(selectSQL []string, all bool) *Model {
	m.options.setUnion(selectSQL, all)
	return m
}

//LastSQL 最后执行生成的SQL语句
func (m *Model) LastSQL() string {
	return m.sql
}

//Error	执行过程中出现的所有错误
func (m *Model) Error() error {
	if len(m.err) > 0 {
		str := fmt.Sprintf("\n[Model Error]:\n %s \n", strings.Join(m.err, "\n"))
		return errors.New(str)
	}
	return nil
}

//Find 查找数据
func (m *Model) Find(dest interface{}) (err error) {
	defer func(){
		m.options = option{}
		if errs := recover(); errs != nil {
			m.err = append(m.err, fmt.Sprintf("%v", errs))
		}
		err = m.Error()
		m.err = m.err[0:0]
	}()
	m.Limit(Limit{
		Offset : 1,
	})
	m.sql = builder.BuildSQL(query, &m.options, nil)

	if m.sql == "" {
		m.err = append(m.err, "[Model Find]:The SQL is null of string")
		return 
	}
	db, err := getDB(m.getDBAlias())
	if  err != nil {
		m.err = append(m.err, err.Error())
		return
	}
	if err = db.Get(dest, m.sql, m.options.whereArgs...); err != nil {
		m.err = append(m.err, err.Error())
		return 
	}
	return 
}

//Select 查询数据
func (m *Model) Select(dest interface{}) (err error) {
	defer func(){
		m.options = option{}
		if errs := recover(); errs != nil {
			m.err = append(m.err, fmt.Sprintf("%v", errs))
		}
		err = m.Error()
		m.err = m.err[0:0]
	}()	
	
	m.sql = builder.BuildSQL(query, &m.options, nil)
	if m.sql == "" {
		m.err = append(m.err, "[Model Find]:The SQL is null of string")
		return 
	}
	db, err := getDB(m.getDBAlias())
	if  err != nil {
		m.err = append(m.err, err.Error())
		return 
	}
	if err = db.Select(dest, m.sql, m.options.whereArgs...); err != nil {
		m.err = append(m.err, err.Error())
		return 
	}
	return 
}

//Add 新增数据
func (m *Model) Add(data interface{}) (id int64, err error) {
	defer func(){
		m.options = option{}
		if errs := recover(); errs != nil {
			id = -1
			m.err = append(m.err, fmt.Sprintf("%v", errs))
		}
		err = m.Error()
		m.err = m.err[0:0]
	}()

	fields := &field{}
	fields.parseData(data)

	m.options.setField(fields.names...)

	m.parseOption()

	m.sql = builder.BuildSQL(insert, &m.options, nil)
	
	db, err := getDB(m.getDBAlias())

	if  err != nil {
		m.err = append(m.err, err.Error())
		id = -1
		return
	}
	result ,err := db.Exec(m.sql, fields.values...)

	if  err != nil {
		m.err = append(m.err, err.Error())
		id = -1 
		return
	}
	lastID, err := result.LastInsertId()
	if err != nil {
		m.err = append(m.err, err.Error())
		id = -1
		return
	}
	id = lastID
	return 
}

//AddAll 新增多条数据
func (m *Model) AddAll(datas ...interface{}) (err error) {
	defer func(){
		m.options = option{}
		if errs := recover(); errs != nil {
			m.err = append(m.err, fmt.Sprintf("%v", errs))
		}
		err = m.Error()
		m.err = m.err[0:0]
	}()
	if len(datas) == 0 {
		m.err = append(m.err, "[Model AddAll]:The datas is null")
		return 
	}

	fields := &field{}
	values, errs := fields.parseDatas(datas...)

	if errs != nil {
		m.err = append(m.err, errs.Error())
		return 
	}

	m.options.setField(fields.names...)
	
	db, errs := getDB(m.getDBAlias())
	if  errs != nil {
		m.err = append(m.err, errs.Error())
		return 
	}
	m.sql = builder.BuildSQL(insert, &m.options, nil)

	tx := db.MustBegin()
	for _, value := range values {
		result := tx.MustExec(m.sql, value...)
		_, errs := result.LastInsertId()
		if errs != nil {
			m.err = append(m.err, errs.Error())
			tx.Rollback()
			return 
		}
	}
	tx.Commit()
	return 
}

//Update 更新数据
func (m *Model) Update(data map[string]interface{}) (num int64, err error) {
	defer func(){
		m.options = option{}
		if errs := recover(); errs != nil {
			m.err = append(m.err, fmt.Sprintf("%v", errs))
		}
		err = m.Error()
		m.err = m.err[0:0]
	}()

	m.sql = builder.BuildSQL(update, &m.options, data)
	db, errs := getDB(m.getDBAlias())
	if  errs != nil {
		m.err = append(m.err, errs.Error())
		num = -1
		return 
	}

	result ,errs := db.Exec(m.sql, m.options.args...)
	if  errs != nil {
		m.err = append(m.err, errs.Error())
		num = -1
		return 
	}

	id, errs := result.RowsAffected()
	if errs != nil {
		m.err = append(m.err, errs.Error())
		num = -1
		return
	}
	num = id
	return 
}

//Delete 删除数据
func (m *Model) Delete() (num int64, err error) {
	defer func(){
		m.options = option{}
		if errs := recover(); errs != nil {
			m.err = append(m.err, fmt.Sprintf("%v", errs))
		}
		err = m.Error()
		m.err = m.err[0:0]
	}()

	m.sql = builder.BuildSQL(delete, &m.options, nil)
	db, errs := getDB(m.getDBAlias())
	if  errs != nil {
		m.err = append(m.err, errs.Error())
		return -1, m.Error()
	}

	result ,errs := db.Exec(m.sql, m.options.whereArgs...)
	if  errs != nil {
		m.err = append(m.err, errs.Error())
		return 
	}

	id, errs := result.RowsAffected()
	if errs != nil {
		m.err = append(m.err, errs.Error())
		return 
	}
	num = id
	return
}

